// Package backup 备份管理
package backup

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"time"

	"github.com/cnssl/cert-deploy-iis/internal/util"
)

// Metadata 备份元数据
type Metadata struct {
	SiteName  string    `json:"site_name"`
	BackupAt  time.Time `json:"backup_at"`
	CertInfo  CertInfo  `json:"cert_info"`
	CertPath  string    `json:"cert_path"`
	KeyPath   string    `json:"key_path"`
}

// CertInfo 证书信息
type CertInfo struct {
	Subject   string    `json:"subject"`
	Serial    string    `json:"serial"`
	NotBefore time.Time `json:"not_before"`
	NotAfter  time.Time `json:"not_after"`
}

// Manager 备份管理器
type Manager struct {
	backupDir    string // 备份根目录
	keepVersions int    // 保留版本数
}

// NewManager 创建备份管理器
func NewManager(backupDir string, keepVersions int) *Manager {
	return &Manager{
		backupDir:    backupDir,
		keepVersions: keepVersions,
	}
}

// Backup 备份证书文件
func (m *Manager) Backup(siteName, certPath, keyPath string, certInfo *CertInfo) (string, error) {
	// 1. 创建备份目录
	timestamp := time.Now().Format("20060102-150405")
	backupPath := filepath.Join(m.backupDir, siteName, timestamp)

	if err := util.EnsureDir(backupPath, 0755); err != nil {
		return "", fmt.Errorf("failed to create backup directory: %w", err)
	}

	// 2. 备份证书文件
	backupCertPath := filepath.Join(backupPath, "cert.pem")
	if err := util.CopyFile(certPath, backupCertPath); err != nil {
		return "", fmt.Errorf("failed to backup certificate: %w", err)
	}

	// 3. 备份私钥文件
	backupKeyPath := filepath.Join(backupPath, "key.pem")
	if err := util.CopyFile(keyPath, backupKeyPath); err != nil {
		return "", fmt.Errorf("failed to backup private key: %w", err)
	}

	// 4. 保存元数据
	metadata := &Metadata{
		SiteName: siteName,
		BackupAt: time.Now(),
		CertPath: certPath,
		KeyPath:  keyPath,
	}

	if certInfo != nil {
		metadata.CertInfo = *certInfo
	}

	metaPath := filepath.Join(backupPath, "metadata.json")
	if err := m.saveMetadata(metaPath, metadata); err != nil {
		return "", fmt.Errorf("failed to save metadata: %w", err)
	}

	// 5. 清理老版本
	if err := m.cleanup(siteName); err != nil {
		// 清理失败不影响备份操作
		// 在实际使用中应该记录警告日志
	}

	return backupPath, nil
}

// ListBackups 列出站点的所有备份
func (m *Manager) ListBackups(siteName string) ([]string, error) {
	siteBackupDir := filepath.Join(m.backupDir, siteName)

	entries, err := os.ReadDir(siteBackupDir)
	if err != nil {
		if os.IsNotExist(err) {
			return []string{}, nil
		}
		return nil, fmt.Errorf("failed to read backup directory: %w", err)
	}

	var backups []string
	for _, entry := range entries {
		if entry.IsDir() {
			backups = append(backups, entry.Name())
		}
	}

	// 按时间排序(最新的在前)
	sort.Sort(sort.Reverse(sort.StringSlice(backups)))

	return backups, nil
}

// GetLatestBackup 获取最新的备份
func (m *Manager) GetLatestBackup(siteName string) (string, error) {
	backups, err := m.ListBackups(siteName)
	if err != nil {
		return "", err
	}

	if len(backups) == 0 {
		return "", fmt.Errorf("no backup found for site: %s", siteName)
	}

	return filepath.Join(m.backupDir, siteName, backups[0]), nil
}

// GetBackupPaths 获取备份的证书和私钥路径
func (m *Manager) GetBackupPaths(backupPath string) (certPath, keyPath string) {
	certPath = filepath.Join(backupPath, "cert.pem")
	keyPath = filepath.Join(backupPath, "key.pem")
	return
}

// LoadMetadata 加载备份元数据
func (m *Manager) LoadMetadata(backupPath string) (*Metadata, error) {
	metaPath := filepath.Join(backupPath, "metadata.json")

	data, err := os.ReadFile(metaPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read metadata: %w", err)
	}

	var metadata Metadata
	if err := json.Unmarshal(data, &metadata); err != nil {
		return nil, fmt.Errorf("failed to parse metadata: %w", err)
	}

	return &metadata, nil
}

// cleanup 清理老版本备份
func (m *Manager) cleanup(siteName string) error {
	backups, err := m.ListBackups(siteName)
	if err != nil {
		return err
	}

	// 如果备份数量超过限制,删除最老的
	if len(backups) > m.keepVersions {
		siteBackupDir := filepath.Join(m.backupDir, siteName)

		for i := m.keepVersions; i < len(backups); i++ {
			oldBackup := filepath.Join(siteBackupDir, backups[i])
			if err := os.RemoveAll(oldBackup); err != nil {
				return fmt.Errorf("failed to remove old backup: %w", err)
			}
		}
	}

	return nil
}

// saveMetadata 保存元数据
func (m *Manager) saveMetadata(path string, metadata *Metadata) error {
	data, err := json.MarshalIndent(metadata, "", "  ")
	if err != nil {
		return err
	}

	return os.WriteFile(path, data, 0644)
}

// DeleteBackup 删除指定备份
func (m *Manager) DeleteBackup(siteName, timestamp string) error {
	backupPath := filepath.Join(m.backupDir, siteName, timestamp)
	return os.RemoveAll(backupPath)
}

// DeleteAllBackups 删除站点的所有备份
func (m *Manager) DeleteAllBackups(siteName string) error {
	siteBackupDir := filepath.Join(m.backupDir, siteName)
	return os.RemoveAll(siteBackupDir)
}
